#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

// 游戏难度设置
#define EASY_ROWS 9
#define EASY_COLS 9
#define EASY_MINES 10

#define MEDIUM_ROWS 16
#define MEDIUM_COLS 16
#define MEDIUM_MINES 40

#define HARD_ROWS 16
#define HARD_COLS 30
#define HARD_MINES 99

// 格子状态
#define HIDDEN 0
#define REVEALED 1
#define FLAGGED 2

// 游戏状态
#define PLAYING 0
#define WIN 1
#define LOSE 2

// 结构体定义
typedef struct {
	int isMine;          // 是否为地雷
	int state;           // 格子状态（隐藏/显示/标记）
	int adjacentMines;   // 周围地雷数
} Cell;

typedef struct {
	Cell **board;        // 游戏棋盘
	int rows;            // 行数
	int cols;            // 列数
	int mineCount;       // 地雷总数
	int flagsPlaced;     // 已标记的地雷数
	int cellsRevealed;   // 已揭示的格子数
	int gameState;       // 游戏状态
	time_t startTime;    // 游戏开始时间
} Game;

typedef struct {
	char playerName[50];
	int time;
	int difficulty; // 0-简单, 1-中等, 2-困难
} HighScore;

// 函数声明
void initializeGame(Game *game, int difficulty);
void placeMines(Game *game, int firstRow, int firstCol);
void calculateAdjacentMines(Game *game);
void printBoard(Game *game);
int revealCell(Game *game, int row, int col);
void flagCell(Game *game, int row, int col);
int checkWin(Game *game);
void saveGame(Game *game, const char *filename);
int loadGame(Game *game, const char *filename);
void saveHighScore(HighScore score);
void displayHighScores(int difficulty);
void freeGame(Game *game);

int main() {
	Game game;
	int choice, difficulty, row, col;
	char filename[100];
	
	srand(time(NULL)); // 初始化随机数种子
	
	printf("=== 扫雷游戏 ===\n");
	
	do {
		printf("\n请选择操作:\n");
		printf("1. 开始新游戏\n");
		printf("2. 加载游戏\n");
		printf("3. 查看排行榜\n");
		printf("4. 退出\n");
		printf("选择: ");
		scanf("%d", &choice);
		
		switch(choice) {
		case 1:
			printf("\n选择难度:\n");
			printf("1. 简单 (%dx%d, %d个地雷)\n", EASY_ROWS, EASY_COLS, EASY_MINES);
			printf("2. 中等 (%dx%d, %d个地雷)\n", MEDIUM_ROWS, MEDIUM_COLS, MEDIUM_MINES);
			printf("3. 困难 (%dx%d, %d个地雷)\n", HARD_ROWS, HARD_COLS, HARD_MINES);
			printf("选择: ");
			scanf("%d", &difficulty);
			
			if(difficulty < 1 || difficulty > 3) {
				printf("无效选择，使用简单难度\n");
				difficulty = 1;
			}
			
			initializeGame(&game, difficulty);
			game.startTime = time(NULL);
			
			// 游戏主循环
			while(game.gameState == PLAYING) {
				printf("\n当前棋盘:\n");
				printBoard(&game);
				
				printf("\n操作: 1-翻开格子, 2-标记地雷, 3-保存游戏, 4-退出当前游戏\n");
				printf("选择操作: ");
				scanf("%d", &choice);
				
				if(choice == 3) {
					printf("输入保存文件名: ");
					scanf("%s", filename);
					saveGame(&game, filename);
					printf("游戏已保存!\n");
					continue;
				}
				
				if(choice == 4) {
					printf("退出当前游戏\n");
					break;
				}
				
				printf("输入行和列 (从1开始): ");
				scanf("%d %d", &row, &col);
				
				// 转换为0-based索引
				row--;
				col--;
				
				if(row < 0 || row >= game.rows || col < 0 || col >= game.cols) {
					printf("无效位置!\n");
					continue;
				}
				
				if(choice == 1) {
					if(!revealCell(&game, row, col)) {
						printf("踩到地雷! 游戏结束!\n");
						game.gameState = LOSE;
					}
				} else if(choice == 2) {
					flagCell(&game, row, col);
				}
				
				if(checkWin(&game)) {
					game.gameState = WIN;
				}
			}
			
			// 游戏结束处理
			if(game.gameState == WIN || game.gameState == LOSE) {
				printf("\n最终棋盘:\n");
				printBoard(&game);
				
				if(game.gameState == WIN) {
					int playTime = (int)difftime(time(NULL), game.startTime);
					printf("恭喜! 你赢了! 用时: %d秒\n", playTime);
					
					// 保存高分记录
					HighScore score;
					printf("输入你的名字: ");
					scanf("%s", score.playerName);
					score.time = playTime;
					score.difficulty = difficulty - 1;
					saveHighScore(score);
				}
			}
			
			freeGame(&game);
			break;
			
		case 2:
			printf("输入要加载的文件名: ");
			scanf("%s", filename);
			if(loadGame(&game, filename)) {
				printf("游戏加载成功!\n");
				
				// 游戏主循环
				while(game.gameState == PLAYING) {
					printf("\n当前棋盘:\n");
					printBoard(&game);
					
					printf("\n操作: 1-翻开格子, 2-标记地雷, 3-保存游戏, 4-退出当前游戏\n");
					printf("选择操作: ");
					scanf("%d", &choice);
					
					if(choice == 3) {
						printf("输入保存文件名: ");
						scanf("%s", filename);
						saveGame(&game, filename);
						printf("游戏已保存!\n");
						continue;
					}
					
					if(choice == 4) {
						printf("退出当前游戏\n");
						break;
					}
					
					printf("输入行和列 (从1开始): ");
					scanf("%d %d", &row, &col);
					
					// 转换为0-based索引
					row--;
					col--;
					
					if(row < 0 || row >= game.rows || col < 0 || col >= game.cols) {
						printf("无效位置!\n");
						continue;
					}
					
					if(choice == 1) {
						if(!revealCell(&game, row, col)) {
							printf("踩到地雷! 游戏结束!\n");
							game.gameState = LOSE;
						}
					} else if(choice == 2) {
						flagCell(&game, row, col);
					}
					
					if(checkWin(&game)) {
						game.gameState = WIN;
					}
				}
				
				// 游戏结束处理
				if(game.gameState == WIN || game.gameState == LOSE) {
					printf("\n最终棋盘:\n");
					printBoard(&game);
					
					if(game.gameState == WIN) {
						int playTime = (int)difftime(time(NULL), game.startTime);
						printf("恭喜! 你赢了! 用时: %d秒\n", playTime);
						
						// 保存高分记录
						HighScore score;
						printf("输入你的名字: ");
						scanf("%s", score.playerName);
						score.time = playTime;
						score.difficulty = game.rows == EASY_ROWS ? 0 : 
						(game.rows == MEDIUM_ROWS ? 1 : 2);
						saveHighScore(score);
					}
				}
				
				freeGame(&game);
			} else {
				printf("加载游戏失败!\n");
			}
			break;
			
		case 3:
			printf("\n查看排行榜:\n");
			printf("1. 简单难度\n");
			printf("2. 中等难度\n");
			printf("3. 困难难度\n");
			printf("选择: ");
			scanf("%d", &difficulty);
			displayHighScores(difficulty - 1);
			break;
			
		case 4:
			printf("谢谢游玩!\n");
			break;
			
		default:
			printf("无效选择!\n");
		}
	} while(choice != 4);
	
	return 0;
}

// 基础管理函数
void initializeGame(Game *game, int difficulty) {
	int rows, cols, mines;
	
	// 根据难度设置参数
	switch(difficulty) {
	case 1:
		rows = EASY_ROWS;
		cols = EASY_COLS;
		mines = EASY_MINES;
		break;
	case 2:
		rows = MEDIUM_ROWS;
		cols = MEDIUM_COLS;
		mines = MEDIUM_MINES;
		break;
	case 3:
		rows = HARD_ROWS;
		cols = HARD_COLS;
		mines = HARD_MINES;
		break;
	default:
		rows = EASY_ROWS;
		cols = EASY_COLS;
		mines = EASY_MINES;
	}
	
	game->rows = rows;
	game->cols = cols;
	game->mineCount = mines;
	game->flagsPlaced = 0;
	game->cellsRevealed = 0;
	game->gameState = PLAYING;
	
	// 分配棋盘内存
	game->board = (Cell**)malloc(rows * sizeof(Cell*));
	for(int i = 0; i < rows; i++) {
		game->board[i] = (Cell*)malloc(cols * sizeof(Cell));
		for(int j = 0; j < cols; j++) {
			game->board[i][j].isMine = 0;
			game->board[i][j].state = HIDDEN;
			game->board[i][j].adjacentMines = 0;
		}
	}
}
void freeGame(Game *game) {
	for(int i = 0; i < game->rows; i++) {
		free(game->board[i]);
	}
	free(game->board);
}
// 游戏逻辑函数
void placeMines(Game *game, int firstRow, int firstCol) {
	int minesPlaced = 0;
	
	while(minesPlaced < game->mineCount) {
		int r = rand() % game->rows;
		int c = rand() % game->cols;
		
		// 确保第一次点击的位置和周围不是地雷
		if((r == firstRow && c == firstCol) || 
			(abs(r - firstRow) <= 1 && abs(c - firstCol) <= 1)) {
			continue;
		}
		
		if(!game->board[r][c].isMine) {
			game->board[r][c].isMine = 1;
			minesPlaced++;
		}
	}
	
	calculateAdjacentMines(game);
}
void calculateAdjacentMines(Game *game) {
	for(int i = 0; i < game->rows; i++) {
		for(int j = 0; j < game->cols; j++) {
			if(game->board[i][j].isMine) {
				continue;
			}
			
			int count = 0;
			for(int di = -1; di <= 1; di++) {
				for(int dj = -1; dj <= 1; dj++) {
					int ni = i + di;
					int nj = j + dj;
					
					if(ni >= 0 && ni < game->rows && nj >= 0 && nj < game->cols) {
						if(game->board[ni][nj].isMine) {
							count++;
						}
					}
				}
			}
			
			game->board[i][j].adjacentMines = count;
		}
	}
}
int revealCell(Game *game, int row, int col) {
	Cell *cell = &game->board[row][col];
	
	// 如果格子已被揭示或标记，直接返回
	if(cell->state != HIDDEN) {
		return 1;
	}
	
	// 如果是第一次点击，放置地雷
	if(game->cellsRevealed == 0) {
		placeMines(game, row, col);
	}
	
	// 如果踩到地雷
	if(cell->isMine) {
		cell->state = REVEALED;
		return 0;
	}
	
	// 递归揭示空白区域
	if(cell->adjacentMines == 0) {
		// 使用栈来避免递归深度过大
		int stackSize = game->rows * game->cols;
		int *stackRow = (int*)malloc(stackSize * sizeof(int));
		int *stackCol = (int*)malloc(stackSize * sizeof(int));
		int stackTop = 0;
		
		// 将当前格子加入栈
		stackRow[stackTop] = row;
		stackCol[stackTop] = col;
		stackTop++;
		
		while(stackTop > 0) {
			// 弹出栈顶元素
			stackTop--;
			int r = stackRow[stackTop];
			int c = stackCol[stackTop];
			
			Cell *currentCell = &game->board[r][c];
			
			// 如果已经揭示过，跳过
			if(currentCell->state == REVEALED) {
				continue;
			}
			
			// 揭示当前格子
			currentCell->state = REVEALED;
			game->cellsRevealed++;
			
			// 如果当前格子周围没有地雷，将周围的格子加入栈
			if(currentCell->adjacentMines == 0) {
				for(int di = -1; di <= 1; di++) {
					for(int dj = -1; dj <= 1; dj++) {
						int nr = r + di;
						int nc = c + dj;
						
						if(nr >= 0 && nr < game->rows && nc >= 0 && nc < game->cols) {
							Cell *neighbor = &game->board[nr][nc];
							if(neighbor->state == HIDDEN && !neighbor->isMine) {
								stackRow[stackTop] = nr;
								stackCol[stackTop] = nc;
								stackTop++;
							}
						}
					}
				}
			}
		}
		
		free(stackRow);
		free(stackCol);
	} else {
		// 直接揭示数字格子
		cell->state = REVEALED;
		game->cellsRevealed++;
	}
	
	return 1;
}
void flagCell(Game *game, int row, int col) {
	Cell *cell = &game->board[row][col];
	
	if(cell->state == HIDDEN) {
		cell->state = FLAGGED;
		game->flagsPlaced++;
	} else if(cell->state == FLAGGED) {
		cell->state = HIDDEN;
		game->flagsPlaced--;
	}
}

int checkWin(Game *game) {
	return game->cellsRevealed == (game->rows * game->cols - game->mineCount);
}
// 界面函数
void printBoard(Game *game) {
	// 打印列号
	printf("   ");
	for(int j = 0; j < game->cols; j++) {
		printf("%2d ", j + 1);
	}
	printf("\n");
	
	// 打印分隔线
	printf("   ");
	for(int j = 0; j < game->cols; j++) {
		printf("---");
	}
	printf("\n");
	
	// 打印棋盘内容
	for(int i = 0; i < game->rows; i++) {
		printf("%2d|", i + 1); // 打印行号
		
		for(int j = 0; j < game->cols; j++) {
			Cell cell = game->board[i][j];
			
			if(cell.state == HIDDEN) {
				printf(" . ");
			} else if(cell.state == FLAGGED) {
				printf(" F ");
			} else { // REVEALED
				if(cell.isMine) {
					printf(" * ");
				} else if(cell.adjacentMines > 0) {
					printf(" %d ", cell.adjacentMines);
				} else {
					printf("   ");
				}
			}
		}
		printf("\n");
	}
	
	printf("地雷数: %d, 已标记: %d\n", game->mineCount, game->flagsPlaced);
}
// 持久化函数
void saveGame(Game *game, const char *filename) {
	FILE *file = fopen(filename, "wb");
	if(file == NULL) {
		printf("无法创建文件!\n");
		return;
	}
	
	// 写入游戏基本信息
	fwrite(&game->rows, sizeof(int), 1, file);
	fwrite(&game->cols, sizeof(int), 1, file);
	fwrite(&game->mineCount, sizeof(int), 1, file);
	fwrite(&game->flagsPlaced, sizeof(int), 1, file);
	fwrite(&game->cellsRevealed, sizeof(int), 1, file);
	fwrite(&game->gameState, sizeof(int), 1, file);
	fwrite(&game->startTime, sizeof(time_t), 1, file);
	
	// 写入棋盘数据
	for(int i = 0; i < game->rows; i++) {
		for(int j = 0; j < game->cols; j++) {
			fwrite(&game->board[i][j], sizeof(Cell), 1, file);
		}
	}
	
	fclose(file);
}
int loadGame(Game *game, const char *filename) {
	FILE *file = fopen(filename, "rb");
	if(file == NULL) {
		return 0;
	}
	
	// 读取游戏基本信息
	fread(&game->rows, sizeof(int), 1, file);
	fread(&game->cols, sizeof(int), 1, file);
	fread(&game->mineCount, sizeof(int), 1, file);
	fread(&game->flagsPlaced, sizeof(int), 1, file);
	fread(&game->cellsRevealed, sizeof(int), 1, file);
	fread(&game->gameState, sizeof(int), 1, file);
	fread(&game->startTime, sizeof(time_t), 1, file);
	
	// 分配棋盘内存
	game->board = (Cell**)malloc(game->rows * sizeof(Cell*));
	for(int i = 0; i < game->rows; i++) {
		game->board[i] = (Cell*)malloc(game->cols * sizeof(Cell));
	}
	
	// 读取棋盘数据
	for(int i = 0; i < game->rows; i++) {
		for(int j = 0; j < game->cols; j++) {
			fread(&game->board[i][j], sizeof(Cell), 1, file);
		}
	}
	
	fclose(file);
	return 1;
}
void saveHighScore(HighScore score) {
	FILE *file = fopen("highscores.dat", "ab");
	if(file == NULL) {
		printf("无法保存高分记录!\n");
		return;
	}
	
	fwrite(&score, sizeof(HighScore), 1, file);
	fclose(file);
}
void displayHighScores(int difficulty) {
	FILE *file = fopen("highscores.dat", "rb");
	if(file == NULL) {
		printf("暂无高分记录!\n");
		return;
	}
	
	HighScore scores[100];
	int count = 0;
	
	// 读取所有记录
	while(fread(&scores[count], sizeof(HighScore), 1, file) == 1) {
		count++;
	}
	fclose(file);
	
	// 筛选指定难度的记录
	HighScore filtered[100];
	int filteredCount = 0;
	
	for(int i = 0; i < count; i++) {
		if(scores[i].difficulty == difficulty) {
			filtered[filteredCount++] = scores[i];
		}
	}
	
	// 按时间排序
	for(int i = 0; i < filteredCount - 1; i++) {
		for(int j = i + 1; j < filteredCount; j++) {
			if(filtered[i].time > filtered[j].time) {
				HighScore temp = filtered[i];
				filtered[i] = filtered[j];
				filtered[j] = temp;
			}
		}
	}
	
	// 显示前10名
	printf("\n=== 高分榜 ===\n");
	if(filteredCount == 0) {
		printf("暂无记录\n");
	} else {
		for(int i = 0; i < filteredCount && i < 10; i++) {
			printf("%d. %s - %d秒\n", i + 1, filtered[i].playerName, filtered[i].time);
		}
	}
}
